﻿using Casamiel.API.Application.Models;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Dapper;
using System.Linq;
using System.Threading.Tasks;
using Casamiel.Infrastructure;
using System.Data;
using Microsoft.Extensions.Options;
using Casamiel.Domain;
using Casamiel.Common;
using System.Globalization;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Http;
using Aliyun.Acs.Core.Exceptions;

namespace Casamiel.API.Application.Services
{
    /// <summary>
    /// Mobile check code service.
    /// </summary>
    public class MobileCheckCodeService : IMobileCheckCode
    {
        private string _connectionString = string.Empty;
        private readonly AliyunSettings _settings;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="settings"></param>
        ///<param name="snapshot"></param>
        public MobileCheckCodeService(IOptionsSnapshot<AliyunSettings> settings, IOptionsSnapshot<CasamielSettings> snapshot)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            if (snapshot == null)
            {
                throw new ArgumentNullException(nameof(snapshot));
            }

            _settings = settings.Value;
            _connectionString = !string.IsNullOrWhiteSpace(snapshot.Value.ConnectionString) ? snapshot.Value.ConnectionString : throw new ArgumentNullException(nameof(snapshot.Value.ConnectionString));
        }
        /// <summary>
        /// Checks the code.
        /// </summary>
        /// <returns>The code.</returns>
        /// <param name="phone">Phone.</param>
        /// <param name="code">Code.</param>
        /// <param name="isCheckOut">If set to <c>true</c> is check out.</param>
        public JObject CheckCode(string phone, string code, bool isCheckOut)
        {
            JObject obj = new JObject();
            if (phone == "18167137787" && code == "8888") {
                obj["Success"] = true;
                obj["msg"] = "ok!";
                return obj;
            }
            DateTime? outdate = null;
            string checkcode = "";
            var checkcodeItem = GetByMobile(phone);
            checkcodeItem.Wait();
            var dt = checkcodeItem.Result;
            if (dt != null) {
                checkcode = dt.Checkcode;
                outdate = dt.Checkcode_outdate;
            } else {
                obj["Success"] = false;
                obj["msg"] = "验证码输入不正确!";
                return obj;
            }
            if (!string.IsNullOrEmpty(code)) {
                if (code.Equals(checkcode, StringComparison.CurrentCultureIgnoreCase)) {
                    #region 检查验证码是否过期
                    if (DateTime.Now > outdate) {
                        obj["Success"] = false;
                        obj["msg"] = "验证码已经过期!";
                    } else {

                        obj["Success"] = true;
                        obj["msg"] = "ok!";
                        if (isCheckOut) {
                            dt.Checkcode_outdate = DateTime.Now;
                            Update(dt).GetAwaiter().GetResult();
                        }
                        //dt.Rows[0]["checkcode_outdate"] = DateTime.Now;
                        //  this.Update(dt.ToMeta("id", new string[] { "id", "checkcode_outdate" }), this.Builder);
                    }
                    #endregion
                } else {
                    obj["Success"] = false;
                    obj["msg"] = "验证码输入不正确!";
                }
            } else {
                obj["Success"] = false;
                obj["msg"] = "验证码输入不正确!";
            }

            //else
            //{
            //    obj["Success"] = false;
            //    obj["msg"] = "请输入验证码!";
            //}
            return obj;
        }

        /// <summary>
        /// Gets the by mobile.
        /// </summary>
        /// <returns>The by mobile.</returns>
        /// <param name="mobile">Mobile.</param>
        private async Task<MobileCheckcode> GetByMobile(string mobile)
        {
            using (var connection = new SqlConnection(_connectionString)) {
                var result = await connection.QueryFirstOrDefaultAsync<MobileCheckcode>("select * from mobile_checkcode where mobile=@mobile", new { mobile }).ConfigureAwait(false);
                return result;
            }
        }

        /// <summary>
        /// Checks the sms code.
        /// </summary>
        /// <returns>The sms code.</returns>
        /// <param name="phone">Phone.</param>
        /// <param name="code">Code.</param>
        /// <param name="isCheckOut">If set to <c>true</c> is check out.</param>
        public JObject CheckSmsCode(string phone, string code, bool isCheckOut)
        {
            JObject obj = new JObject();

            if (phone == "13588888888") {
                obj["code"] = 0;
                obj["msg"] = "ok!";
                return obj;
            }
            if (phone == "18167137787" && code == "8888") {
                obj["code"] = 0;
                obj["msg"] = "ok!";
                return obj;
            }
            DateTime? outdate = null;
            string checkcode = "";
            var checkcodeItem = GetByMobile(phone);
            checkcodeItem.Wait();
            var dt = checkcodeItem.Result;
            if (dt != null) {
                checkcode = dt.Checkcode;
                outdate = dt.Checkcode_outdate;
            }
            if (!string.IsNullOrEmpty(code)) {
                if (code.Equals(checkcode, StringComparison.CurrentCultureIgnoreCase)) {
                    if (isCheckOut) {
                        #region 检查验证码是否过期
                        if (DateTime.Now > outdate) {
                            obj["code"] = -1;
                            obj["msg"] = "验证码已经过期!";
                        } else {
                            obj["code"] = 0;
                            obj["msg"] = "ok!";
                            //dt.Rows[0]["checkcode_outdate"] = DateTime.Now;
                            //  this.Update(dt.ToMeta("id", new string[] { "id", "checkcode_outdate" }), this.Builder);
                        }
                        #endregion
                    } else {
                        obj["code"] = 0;
                        obj["msg"] = "ok!";
                        //dt.Rows[0]["checkcode_outdate"] = DateTime.Now;
                        // this.Update(dt.ToMeta("id", new string[] { "id", "checkcode_outdate" }), this.Builder);
                    }
                } else {
                    obj["code"] = -2;
                    obj["msg"] = "验证码输入不正确!";
                }
            } else {
                obj["code"] = -2;
                obj["msg"] = "请输入验证码!";
            }
            return obj;
        }
        /// <summary>
        /// Checks the sms code async.
        /// </summary>
        /// <returns>The sms code async.</returns>
        /// <param name="phone">Phone.</param>
        /// <param name="code">Code.</param>
        /// <param name="isCheckOut">If set to <c>true</c> is check out.</param>
		public async Task<JObject> CheckSmsCodeAsync(string phone, string code, bool isCheckOut)
        {
            JObject obj = new JObject();
            if (phone == "13588888888") {
                obj["code"] = 0;
                obj["msg"] = "ok!";
                return obj;
            }
            if (phone == "18167137787" && code == "8888") {
                obj["code"] = 0;
                obj["msg"] = "ok!";
                return obj;
            }
            DateTime? outdate = null;
            string checkcode = "";
            var dt = await GetByMobile(phone).ConfigureAwait(false);
            if (dt != null) {
                checkcode = dt.Checkcode;
                outdate = dt.Checkcode_outdate;
            } else {
                obj["code"] = -2;
                obj["msg"] = "验证码输入不正确!";
                return obj;
            }

            if (!string.IsNullOrEmpty(code)) {
                if (code.Equals(checkcode, StringComparison.CurrentCultureIgnoreCase)) {
                    #region 检查验证码是否过期
                    if (DateTime.Now > outdate) {
                        obj["code"] = -1;
                        obj["msg"] = "验证码已经过期!";
                        return obj;
                    } else {
                        obj["code"] = 0;
                        obj["msg"] = "ok!";
                        if (isCheckOut) {
                            //dt.Rows[0]["checkcode_outdate"] = DateTime.Now;
                            dt.Checkcode_outdate = DateTime.Now;
                            await Update(dt).ConfigureAwait(false);
                        }
                        return obj;
                    }
                    #endregion
                } else {
                    obj["code"] = -2;
                    obj["msg"] = "验证码输入不正确!";
                }
            } else {
                obj["code"] = -2;
                obj["msg"] = "验证码输入不正确!";
            }
            return obj;

        }
        /// <summary>
        /// Update the specified entity.
        /// </summary>
        /// <returns>The update.</returns>
        /// <param name="entity">Entity.</param>
        private async Task<int> Update(MobileCheckcode entity)
        {
            using (var connection = new SqlConnection(_connectionString)) {
                var result = await connection.ExecuteAsync("update mobile_checkcode set   send_num=@send_num,Create_time=@Create_time,Checkcode=@Checkcode,Checkcode_outdate=@Checkcode_outdate  where mobile=@mobile", new { Create_time = entity.Create_time, send_num = entity.Send_num, Checkcode = entity.Checkcode, Checkcode_outdate = entity.Checkcode_outdate, Mobile = entity.Mobile }).ConfigureAwait(false);
                return result;
            }
        }
        /// <summary>
        /// Add the specified entity.
        /// </summary>
        /// <returns>The add.</returns>
        /// <param name="entity">Entity.</param>
        private async Task<int> AddAsync(MobileCheckcode entity)
        {
            using (var connection = new SqlConnection(_connectionString)) {
                try {
                    var result = await connection.ExecuteAsync("insert into mobile_checkcode(mobile,send_num,Create_time,Checkcode,Checkcode_outdate) values(@Mobile,@Send_num,@Create_time,@Checkcode,@Checkcode_outdate)", entity).ConfigureAwait(false);
                    return result;
                } catch (SqlException ex) {
                    if (ex.Number != 2627) {
                        Console.WriteLine(ex.Message);
                        return 1;
                    } else {
                        Console.WriteLine(ex.Message);
                        return 0;
                    }

                }
            }
        }
        /// <summary>
        /// Sends the check code.
        /// </summary>
        /// <returns>The check code.</returns>
        /// <param name="mobile">Mobile.</param>
        public async Task<string> SendCheckCodeAsync(string mobile)
        {
            try {
                if (mobile == "18167137787" || mobile == "13588888888") {
                    return "";
                }
                //return "";
                if (string.IsNullOrEmpty(mobile) || mobile.Trim().Length != 11) {
                    return "手机号码有误！";
                }
                mobile = mobile.Trim();
                string msg = "";
                Random rn = new Random();
                string checkcode = "6219";
                //string checkcode = rn.Next(1, 9999).ToString("0000", CultureInfo.CurrentCulture);    //4位随机数,注册更简单
                int checkcodevalid = 3;   //验证码过期时间
                DateTime checkcode_outdate = DateTime.Now.AddMinutes(checkcodevalid);
                DateTime lastSendTime = DateTime.MinValue;
                #region 存储验证码
                int num = 0;
                var item = await GetByMobile(mobile).ConfigureAwait(false);
                //Console.WriteLine(item);
                if (item != null) {
                    lastSendTime = item.Create_time;// Convert.ToDateTime(dt.Rows[0]["create_time"]);
                    if (DateTime.Now.Subtract(lastSendTime).TotalSeconds < 60) {
                        return "60秒内仅能获取一次验证码，请稍后重试!";
                    }

                    if (item.Create_time.ToShortDateString() == DateTime.Now.ToShortDateString()) {
                        int send_num = item.Send_num;
                        if (send_num >= 2000)// ConfigSystemBO.Instance.GetIntValueByCache("SendQuantityPerDay"))
                        {
                            msg = "对不起，同一手机号每天只能发送20次!";//ConfigSystemBO.Instance.GetIntValueByCache("SendQuantityPerDay") + "次!";
                            return msg;
                        }
                        item.Send_num += 1;
                    } else {
                        item.Send_num = 1;
                    }
                    item.Checkcode = checkcode;
                    item.Create_time = DateTime.Now;
                    item.Checkcode_outdate = checkcode_outdate;
                    num = await Update(item).ConfigureAwait(false);
                } else {
                    var row = new MobileCheckcode();
                    row.Mobile = mobile;
                    row.Checkcode = checkcode;
                    row.Send_num = 1;
                    row.Create_time = DateTime.Now;
                    row.Checkcode_outdate = checkcode_outdate;
                    num = await AddAsync(row).ConfigureAwait(false);
                }
                //Console.WriteLine(num);
                //if (num == 0)
                //{
                //    return "验证码发送失败";
                //}
                // System.Threading.Thread.Sleep(2000);
                string signName = _settings.SmsSignName;// "可莎蜜兒";
                var tem = new JObject {
                    ["code"] = checkcode
                };

                string templateParam = tem.ToString();
                string templateCode = _settings.YzmTemplateCode;// "SMS_120115152";
                if (num == 1) {
                    SendSmsResponse response = new SendSmsResponse();
                    response.Code = "OK";

                   // var response = await SmsHelper.SendSms(_settings.accessKey, _settings.accessKeySecret, mobile, signName, templateParam, templateCode, "").ConfigureAwait(false);
                    //Console.WriteLine(response.Code);

                    if (response.Code != "OK") {

                        Console.WriteLine($"手机号{mobile}，错误码{response.Code}");
                        if (_settings.SmsSignName == "皇冠幸福里" || _settings.SmsSignName == "CMLab") {
                            var entity = new ErrorLog {
                                // entity.Url = context.HttpContext.Request.Path;
                                Loginfo = $"手机号{mobile}，错误码{response.Code}",
                                OPTime = DateTime.Now
                            };
                            // entity.StackTrace = context.Exception.StackTrace;

                            using (var connection = new SqlConnection(_connectionString)) {
                                string sql = "INSERT INTO sa_error_log (OPTime ,Url,[Loginfo],[StackTrace])VALUES(@OPTime,@Url,@Loginfo,@StackTrace)";
                                var result = connection.Execute(sql, entity);
                            }
                            var checkcodeModel = await GetByMobile(mobile).ConfigureAwait(false);
                            checkcodeModel.Send_num -= 1;
                            checkcodeModel.Checkcode_outdate = checkcodeModel.Create_time.AddMinutes(-3);
                            await Update(checkcodeModel).ConfigureAwait(false);
                            return "验证码发送失败";
                        }

                        var TtsCode = "TTS_169505418";//可莎
                        var CalledShowNumber = "057428840620";
                        if (_settings.SmsSignName == "东哥食品") {
                            TtsCode = "TTS_174720139";
                            CalledShowNumber = "05806334110";
                        }
                        IClientProfile profile = DefaultProfile.GetProfile(
    "cn-hangzhou",
    _settings.accessKey,
    _settings.accessKeySecret);
                        DefaultAcsClient client = new DefaultAcsClient(profile);
                        CommonRequest request = new CommonRequest {
                            Method = MethodType.POST,
                            Domain = "dyvmsapi.aliyuncs.com",
                            Version = "2017-05-25",
                            Action = "SingleCallByTts"
                        };
                        // request.Protocol = ProtocolType.HTTP;
                        request.AddQueryParameters("CalledShowNumber", CalledShowNumber);//显示号码
                        request.AddQueryParameters("CalledNumber", mobile);
                        request.AddQueryParameters("TtsCode", TtsCode);
                        request.AddQueryParameters("TtsParam", "{\"code\":\"" + item.Checkcode + "\"}");
                        try {
                            var rsp = client.GetCommonResponse(request);
                            Console.WriteLine(System.Text.Encoding.Default.GetString(rsp.HttpResponse.Content));
                            return "正在发送语音验证码";
                        } catch (ClientException e) {
                            Console.WriteLine(e);
                            var entity = new ErrorLog {
                                // entity.Url = context.HttpContext.Request.Path;
                                Loginfo = $"手机号{mobile}，错误码{e.ErrorMessage}",
                                OPTime = DateTime.Now
                            };
                            // entity.StackTrace = context.Exception.StackTrace;

                            using (var connection = new SqlConnection(_connectionString)) {
                                string sql = "INSERT INTO sa_error_log (OPTime ,Url,[Loginfo],[StackTrace])VALUES(@OPTime,@Url,@Loginfo,@StackTrace)";
                                var result = connection.Execute(sql, entity);
                            }
                            var checkcodeModel = await GetByMobile(mobile).ConfigureAwait(false);
                            checkcodeModel.Send_num -= 1;
                            checkcodeModel.Checkcode_outdate = checkcodeModel.Create_time.AddMinutes(-3);
                            await Update(checkcodeModel).ConfigureAwait(false);
                            return "验证码发送失败";
                        }


                    }
                }
            } catch {
                throw;
            }
            #endregion
            return "";
        }

    }
}
